//
//  PXICustomScroller.m
//  PXIView
//
//  Created by decaf on 11/23/04.
//  Copyright 2004 __MyCompanyName__. All rights reserved.
//

#import "PXICustomScroller.h"


@implementation PXICustomScroller

- (id) init
{
	[super init];
	if ( self )
	{
		myScrollPat = [NSImage imageNamed: @"scrlpat"];
		uparrow = [NSImage imageNamed: @"uparrow"];
		huparrow = [NSImage imageNamed: @"huparrow"];
		downarrow = [NSImage imageNamed: @"dnarrow"];
		hdownarrow = [NSImage imageNamed: @"hdnarrow"];
		
		scale = 1;
		myFloatValue = 1.0;
	}
	return self;
}

+ (float)scrollerWidth
{
	return 17;
}

+ (float)scrollerWidthForControlSize:(NSControlSize)controlSize
{
	return 17;
}

- (float)scale {
    return scale;
}

- (void)setScale:(float)newScale {
    if (scale != newScale) {
        scale = newScale;
    }
}

- (float)myFloatValue {
    return myFloatValue;
}

- (void)setMyFloatValue:(float)newMyFloatValue {
    if (myFloatValue != newMyFloatValue) {
        myFloatValue = newMyFloatValue;
    }
}

- (NSScrollArrowPosition)arrowsPosition
{
	return NSScrollerArrowsNone;
}

- (void)checkSpaceForParts
{
	; // Unimplemented
}

- (NSControlSize)controlSize
{
	return NSRegularControlSize;
}

- (NSControlTint)controlTint
{
	return NSClearControlTint;
}

- (void)drawArrow:(NSScrollerArrow)arrow highlight:(BOOL)flag
{
	; // Unimplemented
}

- (void)drawKnob
{
	; // Unimplemented
}

- (void)drawParts
{
	; // Well, that sucked.
}

- (void)highlight:(BOOL)flag
{
	; // Unimplemented
}

- (NSScrollerPart)hitPart
{
	return myHitPart;
}

- (float)knobProportion
{
	return 0;
}

- (NSRect)rectForPart:(NSScrollerPart)aPart
{
	NSRect fakeKnobSlotRect;
	switch ( aPart )
	{
		case NSScrollerIncrementLine:
			return NSMakeRect( 1, [self frame].size.height - 15, 16, 15 );
			break;
		case NSScrollerIncrementPage:
			return NSMakeRect( [self bounds].origin.x + 1, [self rectForPart:NSScrollerKnob].origin.y, [self bounds].size.width - 1, [self bounds].size.height - 15 - [self rectForPart:NSScrollerKnob].origin.y );
			break;
		case NSScrollerDecrementLine:
			return NSMakeRect( 1, 0, 16, 15 );
			break;
		case NSScrollerDecrementPage:
			return NSMakeRect( [self bounds].origin.x + 1, [self bounds].origin.x + 1, [self bounds].size.width - 1, 15 + [self rectForPart:NSScrollerKnob].origin.y );
			break;			
		case NSScrollerKnob:
			fakeKnobSlotRect = [self rectForPart:NSScrollerKnobSlot];
			fakeKnobSlotRect = NSMakeRect ( fakeKnobSlotRect.origin.x, fakeKnobSlotRect.origin.y, fakeKnobSlotRect.size.width, fakeKnobSlotRect.size.height - 1 );
			return NSMakeRect( 2, fakeKnobSlotRect.size.height - ( myFloatValue * ( fakeKnobSlotRect.size.height - 16 ) ), 14 , 15 );
			break;
		case NSScrollerKnobSlot:
			return NSMakeRect( [self bounds].origin.x + 1, [self bounds].origin.y + 15, [self bounds].size.width - 1, [self bounds].size.height - 30 );
			break;
		default:
			return NSZeroRect;
			break;
	}
}

- (void)setArrowsPosition:(NSScrollArrowPosition)location
{
	; // Unimplemented
}

- (void)setControlSize:(NSControlSize)controlSize
{
	; // Unimplemented
}

- (void)setControlTint:(NSControlTint)controlTint
{
	; // Unimplemented
}

- (void)setFloatValue:(float)aFloat knobProportion:(float)knobProp
{
	scale = knobProp;
	myFloatValue = aFloat;
	[self setNeedsDisplay:YES];
}

- (float)floatValue
{
	return myFloatValue;
}

- (NSScrollerPart)testPart:(NSPoint)aPoint
{
	return NSScrollerNoPart;
}

- (void)trackKnob:(NSEvent *)theEvent
{
	; // Unimplemented
}

- (void)trackScrollButtons:(NSEvent *)theEvent
{
	; // Unimplemented
}

- (NSUsableScrollerParts)usableParts
{
	return NSNoScrollerParts;
}

- (void) drawRect:(NSRect)rect
{
	[[NSGraphicsContext currentContext] setShouldAntialias:NO];

	NSRect bgrect = [self rectForPart:NSScrollerKnobSlot];
	NSRect knobRect = [self rectForPart:NSScrollerKnob];
	NSRect upArrowRect = [self rectForPart:NSScrollerIncrementLine];
	NSRect downArrowRect = [self rectForPart:NSScrollerDecrementLine];

	if ( ! [self isEnabled] )
	{
		// Draw dead scroll bar.
		[[NSColor whiteColor] set];
		[NSBezierPath fillRect:bgrect];
		[[NSColor blackColor] set];
		[NSBezierPath strokeRect:bgrect];
				
		[[NSColor whiteColor] set];
		[NSBezierPath fillRect:downArrowRect];
		[[NSColor blackColor] set];
		[NSBezierPath strokeRect:downArrowRect];	
		[downarrow compositeToPoint:NSMakePoint(2, 1) operation:NSCompositeSourceOver];
		
		[[NSColor whiteColor] set];
		[NSBezierPath fillRect:upArrowRect];
		[[NSColor blackColor] set];
		[NSBezierPath strokeRect:upArrowRect];
		[uparrow compositeToPoint:NSMakePoint(2, [self frame].size.height - 14) operation:NSCompositeCopy];
	}
	else
	{
		// Draw live scrollbar.
		[[NSColor colorWithPatternImage:myScrollPat] set];
		[NSBezierPath fillRect:bgrect];
		[[NSColor blackColor] set];
		[NSBezierPath strokeRect:bgrect];

		[[NSColor whiteColor] set];
		[NSBezierPath fillRect:downArrowRect];
		[[NSColor blackColor] set];
		[NSBezierPath strokeRect:downArrowRect];	
		[downarrow compositeToPoint:NSMakePoint(2, 1) operation:NSCompositeSourceOver];
		if ( downArrowOn )
		{
			[hdownarrow compositeToPoint:NSMakePoint(2, 1) operation:NSCompositeSourceOver];
		}	
		
		[[NSColor whiteColor] set];
		[NSBezierPath fillRect:upArrowRect];
		[[NSColor blackColor] set];
		[NSBezierPath strokeRect:upArrowRect];
		[uparrow compositeToPoint:NSMakePoint(2, [self frame].size.height - 14) operation:NSCompositeCopy];
		if ( upArrowOn )
		{
			[huparrow compositeToPoint:NSMakePoint(2, [self frame].size.height - 14) operation:NSCompositeSourceOver];
		}
		
		[[NSColor whiteColor] set];
		[NSBezierPath fillRect:knobRect];
		[[NSColor blackColor] set];
		[NSBezierPath strokeRect:knobRect];	
		
	}
}

- (void) setTarget:(id)whatTarget
{
	myTarget = whatTarget;
}

- (void) setAction:(SEL)whatAction
{
	myAction = whatAction;
}

- (int)tag {
    return myTag;
}

- (void)setTag:(int)newMyTag {
    if (myTag != newMyTag) {
        myTag = newMyTag;
    }
}

- (void) mouseDown: (NSEvent*)theEvent
{
	
	// NOTE: Increment and decrement are flipped
	// for reasons I don't fully understand.
	// Trust me, it's that way on purpose.
	
	NSPoint clickPt = [self convertPoint:[theEvent locationInWindow] fromView:nil];
	
	float changeFactor;
	float scroll_root = clickPt.y;
	float scroll_current;
	float scroll_adjust;
	float scroll_x;
	
	BOOL delayOnce = YES;
	
	if ( [self isEnabled] )
	{
		
		if ( NSPointInRect( clickPt, [self rectForPart:NSScrollerKnob ] ) )
		{
			scroll_adjust = [self rectForPart:NSScrollerKnob].origin.y - scroll_root;
						
			while ( [[self window] nextEventMatchingMask:NSLeftMouseUpMask untilDate:nil inMode:NSEventTrackingRunLoopMode dequeue:YES] == nil )
			{
			// Thumb dragging.
				
			// THE PLAN
			// Convert the y coordinate into a float value and
			// let the knob chase the cursor.
				
			// Note: make sure the y is within the track rect
								
				scroll_x = ( [self convertPoint:[[self window] mouseLocationOutsideOfEventStream] fromView:nil].x );
							 
				if ( ( scroll_x < - 32 ) || ( scroll_x > [self rectForPart:NSScrollerKnobSlot].size.width + 32 ) )
				{
					myFloatValue = 1 - ( ( scroll_root - 15 + scroll_adjust ) / ( [self rectForPart:NSScrollerKnobSlot].size.height - 15 ) );
				}
				else
				{
					myFloatValue = 1 - ( ( [self convertPoint:[[self window] mouseLocationOutsideOfEventStream] fromView:nil].y - 15 + scroll_adjust ) / ( [self rectForPart:NSScrollerKnobSlot].size.height - 15 ) );
				}
				
				if ( myFloatValue > 1 )
				{
					myFloatValue = 1;
				}
				else if ( myFloatValue < 0 )
				{
					myFloatValue = 0;
				}
				
				myHitPart = NSScrollerKnob;
								
				[myTarget performSelector:myAction withObject:self];
				
				[self setNeedsDisplay:YES];	
								
			}
			
			return;
		}
		
		else
		
		{
			
			do
			{
			
				// LINE BY LINE
				
				if ( NSPointInRect( clickPt, [self rectForPart:NSScrollerDecrementLine] ) )
				{
					
					// DecrementLine
					
					downArrowOn = YES;
										
					myHitPart = NSScrollerIncrementLine;
										
					[myTarget performSelector:myAction withObject:self];
					
					[self setNeedsDisplay:YES];			
					
				}
				else if ( NSPointInRect( clickPt, [self rectForPart:NSScrollerIncrementLine] ) )
				{
					
					// IncrementLine
					
					upArrowOn = YES;
										
					myHitPart = NSScrollerDecrementLine;
										
					[myTarget performSelector:myAction withObject:self];
					
					[self setNeedsDisplay:YES];
				}
				else if ( NSPointInRect( clickPt, [self rectForPart:NSScrollerIncrementPage] ) )
				{
					
					// IncrementPage
					
					myHitPart = NSScrollerDecrementPage;
										
					[myTarget performSelector:myAction withObject:self];
					
					[self setNeedsDisplay:YES];
				}
				else if ( NSPointInRect( clickPt, [self rectForPart:NSScrollerDecrementPage] ) )
				{
					
					// DecrementPage
					
					myHitPart = NSScrollerIncrementPage;
					
					[myTarget performSelector:myAction withObject:self];
					
					[self setNeedsDisplay:YES];
				}		
				else
				{
					// Zilch
					myHitPart = NSScrollerNoPart;
				}
				
				// On the first click, delay for one half second
				// This lets the user comfortably scroll line by
				// line, so the scroll bar doesn't take off like
				// some kind of crazed contraption from computer
				// hell.
				
				if ( delayOnce && [[self window] nextEventMatchingMask:NSLeftMouseUpMask untilDate:[NSDate dateWithTimeIntervalSinceNow:0.5] inMode:NSEventTrackingRunLoopMode dequeue:YES] != nil )
				{
					downArrowOn = NO;
					upArrowOn = NO;
					[self setNeedsDisplay:YES];
					return;
				}
				else
				{
					delayOnce = NO;
				}

			} while ( [[self window] nextEventMatchingMask:NSLeftMouseUpMask untilDate:[NSDate dateWithTimeIntervalSinceNow:0.1] inMode:NSEventTrackingRunLoopMode dequeue:YES] == nil );
		}
	}

	downArrowOn = NO;
	upArrowOn = NO;
	[self setNeedsDisplay:YES];
	
}

- (void) mouseUp: (NSEvent*)theEvent
{
	downArrowOn = NO;
	upArrowOn = NO;
	[self setNeedsDisplay:YES];
}

- (void) dealloc
{
	[myScrollPat release];
}

@end
